package com.ruoyi.myutils;


import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.FeatureIterator;
import org.geotools.geojson.GeoJSONUtil;
import org.geotools.geojson.geom.GeometryJSON;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.WKTWriter;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;




@Slf4j
public class ShpGeoJsonConverter {

    private static final String TEMP_DIR = System.getProperty("java.io.tmpdir");
    private static final String SHP_EXTENSION = ".shp";
    private static final WKTWriter WKT_WRITER = new WKTWriter(); // 线程安全，可复用
    private static final WKTReader WKT_READER = new WKTReader(); // 用于验证WKT

    private static WKTReader reader = new WKTReader();

    private static final String GEO_JSON_TYPE="GeometryCollection";

    private static final String WKT_TYPE="GEOMETRYCOLLECTION";


    public static String jsonToWkt(JSONObject jsonObject) {
        String wkt = null;
        String type = jsonObject.getString("type");
        GeometryJSON gJson = new GeometryJSON(16);
        try {
            // {"geometries":[{"coordinates":[4,6],"type":"Point"},{"coordinates":[[4,6],[7,10]],"type":"LineString"}],"type":"GeometryCollection"}
            if(ShpGeoJsonConverter.GEO_JSON_TYPE.equals(type)){
                // 由于解析上面的json语句会出现这个geometries属性没有采用以下办法
                JSONArray geometriesArray = jsonObject.getJSONArray("geometries");
                // 定义一个数组装图形对象
                int size = geometriesArray.size();
                Geometry[] geometries=new Geometry[size];
                for (int i=0;i<size;i++){
                    String str = geometriesArray.get(i).toString();
                    // 使用GeoUtil去读取str
                    Reader reader = GeoJSONUtil.toReader(str);
                    Geometry geometry = gJson.read(reader);
                    geometries[i]=geometry;
                }
                GeometryCollection geometryCollection = new GeometryCollection(geometries,new GeometryFactory());
                wkt=geometryCollection.toText();
            }else {
                Reader reader = GeoJSONUtil.toReader(jsonObject.toString());
                Geometry read = gJson.read(reader);
                wkt=read.toText();
            }


        } catch (IOException e){
            System.out.println("GeoJson转WKT出现异常");
            e.printStackTrace();
        }
        return wkt;
    }


    public static String multipartFileShp2GeoJson(MultipartFile[] shpFiles) {
        List<Geometry> geometries = new ArrayList<>();
        Path tempDir = null;

        try {
            tempDir = createTempDirectory();
            log.info("临时目录创建成功: {}", tempDir);

            String shpFilePath = saveUploadedFiles(shpFiles, tempDir);
            if (shpFilePath == null) {
                log.error("未找到SHP文件");
                return null;
            }

            geometries = shpToGeometries(shpFilePath);
            log.info("成功转换 {} 个几何对象", geometries.size());

        } catch (Exception e) {
            log.error("处理SHP文件时发生错误", e);
        } finally {
            deleteTempDirectory(tempDir);
        }

        if (!geometries.isEmpty()) {
            GeometryFactory factory = geometries.get(0).getFactory();
            GeometryCollection collection = factory.createGeometryCollection(
                    geometries.toArray(new Geometry[0]));
            return geometryToWkt(collection);
        }

        return null;
    }


    private static String geometryToWkt(Geometry geometry) {
        if (geometry == null) {
            return null;
        }
        return WKT_WRITER.write(geometry); // 使用标准WKTWriter生成严格符合规范的WKT
    }

    private static List<Geometry> shpToGeometries(String filePath) {
        List<Geometry> geometries = new ArrayList<>();
        FileDataStore store = null;
        FeatureIterator<SimpleFeature> features = null;

        try {
            System.setProperty("org.geotools.referencing.forceXY", "true");
            store = FileDataStoreFinder.getDataStore(new File(filePath));
            features = store.getFeatureSource().getFeatures().features();

            CoordinateReferenceSystem sourceCRS = getSourceCRS(store);
            CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:4326");
            MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, true);

            while (features.hasNext()) {
                SimpleFeature feature = features.next();
                Geometry geometry = (Geometry) feature.getDefaultGeometry();
                if (geometry != null) {
                    Geometry transformedGeometry = JTS.transform(geometry, transform);
                    geometries.add(transformedGeometry);
                }
            }
        } catch (Exception e) {
            log.error("处理SHP文件时发生错误", e);
        } finally {
            closeQuietly(features);
            disposeQuietly(store);
        }

        return geometries;
    }




    private static Path createTempDirectory() throws IOException {
        String uuid = UUID.randomUUID().toString();
        return Files.createDirectories(Paths.get(TEMP_DIR, "shp_" + uuid));
    }

    private static String saveUploadedFiles(MultipartFile[] shpFiles, Path tempDir) throws IOException {
        String shpFilePath = null;

        for (MultipartFile file : shpFiles) {
            if (file.isEmpty()) continue;

            String originalFilename = file.getOriginalFilename();
            if (originalFilename == null) continue;

            Path filePath = tempDir.resolve(originalFilename);
            file.transferTo(filePath.toFile());
            log.info("已保存文件: {}", filePath);

            if (originalFilename.toLowerCase().endsWith(SHP_EXTENSION)) {
                shpFilePath = filePath.toString();
            }
        }

        return shpFilePath;
    }

    private static List<String> shpToWkt(String filePath) {
        if (filePath == null || !Files.exists(Paths.get(filePath))) {
            log.error("文件路径不存在: {}", filePath);
            return Collections.emptyList();
        }

        List<String> wktList = new ArrayList<>();
        FileDataStore store = null;
        FeatureIterator<SimpleFeature> features = null;

        try {
            // 强制使用XY坐标轴顺序
            System.setProperty("org.geotools.referencing.forceXY", "true");

            store = FileDataStoreFinder.getDataStore(new File(filePath));
            SimpleFeatureSource featureSource = store.getFeatureSource();
            features = featureSource.getFeatures().features();

            CoordinateReferenceSystem sourceCRS = getSourceCRS(store);
            CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:4326");

            MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, true);

            while (features.hasNext()) {
                SimpleFeature feature = features.next();
                Geometry geometry = (Geometry) feature.getDefaultGeometry();
                if (geometry != null) {
                    Geometry transformedGeometry = JTS.transform(geometry, transform);
                    String wkt = geometryToWkt(transformedGeometry);

                    if (isValidWkt(wkt)) {
                        wktList.add(wkt);
                        log.trace("生成有效WKT: {}", wkt);
                    } else {
                        log.error("无效WKT格式，已跳过: {}", wkt);
                    }
                }
            }
        } catch (IOException | FactoryException | TransformException e) {
            log.error("处理SHP文件时发生错误", e);
        } finally {
            closeQuietly(features);
            disposeQuietly(store);
        }

        return wktList;
    }

    private static CoordinateReferenceSystem getSourceCRS(FileDataStore store) throws IOException {
        SimpleFeatureType schema = store.getSchema();
        CoordinateReferenceSystem crs = schema.getCoordinateReferenceSystem();
        if (crs == null) {
            log.warn("无法获取SHP文件的坐标系，使用默认WGS84");
            try {
                return CRS.decode("EPSG:4326");
            } catch (FactoryException e) {
                throw new RuntimeException("无法创建默认坐标系", e);
            }
        }
        return crs;
    }

    private static boolean isValidWkt(String wkt) {
        if (wkt == null || wkt.trim().isEmpty()) {
            return false;
        }
        try {
            // 尝试解析WKT，验证其格式
            WKT_READER.read(wkt);
            return true;
        } catch (ParseException e) {
            log.error("无效的WKT格式: {}", wkt, e);
            return false;
        }
    }

    private static void closeQuietly(FeatureIterator<?> iterator) {
        if (iterator != null) {
            try {
                iterator.close();
            } catch (Exception e) {
                log.warn("关闭FeatureIterator失败", e);
            }
        }
    }

    private static void disposeQuietly(FileDataStore store) {
        if (store != null) {
            try {
                store.dispose();
            } catch (Exception e) {
                log.warn("关闭FileDataStore失败", e);
            }
        }
    }

    private static void deleteTempDirectory(Path directory) {
        if (directory == null) return;

        try {
            Files.walk(directory)
                    .sorted(java.util.Comparator.reverseOrder())
                    .map(Path::toFile)
                    .forEach(File::delete);
            log.info("临时目录已删除: {}", directory);
        } catch (IOException e) {
            log.error("删除临时目录失败: {}", directory, e);
        }
    }


    public static String Shp2GeoJson(String shpFilePath) {
        List<Geometry> geometries = new ArrayList<>();
        Path tempDir = null;

        try {

            geometries = shpToGeometries(shpFilePath);
            log.info("成功转换 {} 个几何对象", geometries.size());

        } catch (Exception e) {
            log.error("处理SHP文件时发生错误", e);
        } finally {
            deleteTempDirectory(tempDir);
        }

        if (!geometries.isEmpty()) {
            GeometryFactory factory = geometries.get(0).getFactory();
            GeometryCollection collection = factory.createGeometryCollection(
                    geometries.toArray(new Geometry[0]));
            return geometryToWkt(collection);
        }

        return null;
    }
}
